home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / PROGTOOL / GWMALLOC.ZIP;1 / GWMALLOC.TAR / gw_malloc / chunk.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-08  |  64.6 KB  |  2,282 lines

  1. /*
  2.  * memory chunk low-level allocation routines
  3.  *
  4.  * Copyright 1992 by Gray Watson and the Antaire Corporation
  5.  *
  6.  * This file is part of the malloc-debug package.
  7.  *
  8.  * This library is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Library General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2 of the License, or (at your option) any later version.
  12.  *
  13.  * This library is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Library General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Library General Public
  19.  * License along with this library (see COPYING-LIB); if not, write to the
  20.  * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21.  *
  22.  * The author of the program may be contacted at gray.watson@antaire.com
  23.  */
  24.  
  25. /*
  26.  * This file contains algorithm level routine for the heap.  They handle the
  27.  * manipulation and administration of chunks of memory.
  28.  */
  29.  
  30. #define MALLOC_DEBUG_DISABLE
  31.  
  32. #include "malloc.h"
  33. #include "malloc_loc.h"
  34.  
  35. #include "chunk.h"
  36. #include "chunk_loc.h"
  37. #include "compat.h"
  38. #include "conf.h"
  39. #include "dbg_values.h"
  40. #include "error.h"
  41. #include "error_val.h"
  42. #include "heap.h"
  43. #include "version.h"
  44.  
  45. #if INCLUDE_RCS_IDS
  46. LOCAL    char    *rcs_id =
  47.   "$Id: chunk.c,v 1.29 1993/04/05 22:29:52 gray Exp $";
  48. #endif
  49.  
  50. /* checking information */
  51. #define MIN_FILE_LENGTH            3        /* min "[a-zA-Z].c" length */
  52. #define MAX_FILE_LENGTH           40        /* max __FILE__ length */
  53. #define MAX_LINE_NUMBER        10000        /* max __LINE__ value */
  54.  
  55. #define FREE_COLUMN            5        /* for dump_free formatting */
  56. #define FREE_CHAR        '\305'        /* to blank free space with */
  57.  
  58. /* free lists of bblocks and dblocks */
  59. LOCAL    bblock_t    *free_bblock[LARGEST_BLOCK + 1];
  60. LOCAL    dblock_t    *free_dblock[BASIC_BLOCK];
  61.  
  62. /* administrative structures */
  63. LOCAL    bblock_adm_t    *bblock_adm_head = NULL; /* pointer to 1st bb_admin */
  64. LOCAL    bblock_adm_t    *bblock_adm_tail = NULL; /* pointer to last bb_admin */
  65.  
  66. /* user information shifts for display purposes */
  67. LOCAL    int        pnt_below_adm    = 0;    /* add to pnt for display */
  68. LOCAL    int        pnt_total_adm    = 0;    /* total adm per pointer */
  69.  
  70. /* memory stats */
  71. LOCAL    long        alloc_current    = 0;    /* current memory usage */
  72. LOCAL    long        alloc_cur_given    = 0;    /* current mem given */
  73. LOCAL    long        alloc_maximum    = 0;    /* maximum memory usage  */
  74. LOCAL    long        alloc_max_given    = 0;    /* maximum mem given  */
  75. LOCAL    long        alloc_total    = 0;    /* total allocation */
  76. LOCAL    long        alloc_one_max    = 0;    /* maximum at once */
  77. LOCAL    int        free_space_count = 0;    /* count the free bytes */
  78.  
  79. /* pointer stats */
  80. LOCAL    long        alloc_cur_pnts    = 0;    /* current pointers */
  81. LOCAL    long        alloc_max_pnts    = 0;    /* maximum pointers */
  82. LOCAL    long        alloc_tot_pnts    = 0;    /* current pointers */
  83.  
  84. /* admin counts */
  85. LOCAL    int        bblock_adm_count = 0;    /* count of bblock_admin */
  86. LOCAL    int        dblock_adm_count = 0;    /* count of dblock_admin */
  87. LOCAL    int        bblock_count     = 0;    /* count of basic-blocks */
  88. LOCAL    int        dblock_count     = 0;    /* count of divided-blocks */
  89.  
  90. /* alloc counts */
  91. EXPORT    int        _calloc_count    = 0;    /* # callocs, done in alloc */
  92. LOCAL    int        free_count    = 0;    /* count the frees */
  93. LOCAL    int        malloc_count    = 0;    /* count the mallocs */
  94. LOCAL    int        realloc_count    = 0;    /* count the reallocs */
  95.  
  96. /************************* fence-post error functions ************************/
  97.  
  98. /*
  99.  * check PNT of SIZE for fence-post magic numbers, returns ERROR or NOERROR
  100.  */
  101. LOCAL    int    fence_read(const char * file, const unsigned int line,
  102.                char * pnt, unsigned int size)
  103. {
  104.   long        top, *longp;
  105.   
  106.   /*
  107.    * write magic numbers into block in bottom of allocation
  108.    *
  109.    * WARNING: assuming a word-boundary here
  110.    */
  111.   for (longp = (long *)pnt; longp < (long *)(pnt + FENCE_BOTTOM); longp++)
  112.     if (*longp != FENCE_MAGIC_BASE) {
  113.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  114.     _malloc_message("under fence on pointer '%#lx' alloced in '%s:%u'",
  115.             CHUNK_TO_USER(pnt), file, line);
  116.       malloc_errno = MALLOC_UNDER_FENCE;
  117.       _malloc_perror("fence_read");
  118.       return ERROR;
  119.     }
  120.   
  121.   /*
  122.    * write magic numbers into block in top of allocation
  123.    *
  124.    * WARNING: not guaranteed a word-boundary here
  125.    */
  126.   for (longp = (long *)(pnt + size - FENCE_TOP); longp < (long *)(pnt + size);
  127.        longp++) {
  128.     bcopy(longp, &top, sizeof(long));
  129.     if (top != FENCE_MAGIC_TOP) {
  130.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  131.     _malloc_message("over fence on pointer '%#lx' alloced in '%s:%u'",
  132.             CHUNK_TO_USER(pnt), file, line);
  133.       malloc_errno = MALLOC_OVER_FENCE;
  134.       _malloc_perror("fence_read");
  135.       return ERROR;
  136.     }
  137.   }
  138.   
  139.   return NOERROR;
  140. }
  141.  
  142. /*
  143.  * load PNT of SIZE bytes with fence-post magic numbers
  144.  */
  145. LOCAL    void    fence_write(char * pnt, unsigned int size)
  146. {
  147.   long        top = FENCE_MAGIC_TOP;
  148.   long        *longp;
  149.   
  150.   /* write magic numbers into block in bottom of allocation */
  151.   for (longp = (long *)pnt; longp < (long *)(pnt + FENCE_BOTTOM); longp++)
  152.     *longp = FENCE_MAGIC_BASE;
  153.   
  154.   /* write magic numbers into block in top of allocation */
  155.   /* WARNING: not guaranteed a word-boundary here */
  156.   for (longp = (long *)(pnt + size - FENCE_TOP); longp < (long *)(pnt + size);
  157.        longp++)
  158.     bcopy(&top, longp, sizeof(long));
  159. }
  160.  
  161. /************************** administration functions *************************/
  162.  
  163. /*
  164.  * startup the low level malloc routines
  165.  */
  166. EXPORT    int    _chunk_startup(void)
  167. {
  168.   int    binc;
  169.   
  170.   /* verify some conditions */
  171.   if (BB_PER_ADMIN <= 2
  172.       || sizeof(bblock_adm_t) > BLOCK_SIZE
  173.       || DB_PER_ADMIN < (1 << (BASIC_BLOCK - SMALLEST_BLOCK))
  174.       || sizeof(dblock_adm_t) > BLOCK_SIZE
  175.       || SMALLEST_BLOCK < ALLOCATION_ALIGNMENT_IN_BITS) {
  176.     malloc_errno = MALLOC_BAD_SETUP;
  177.     _malloc_perror("_chunk_startup");
  178.     return ERROR;
  179.   }
  180.   
  181.   /* align the base pointer */
  182.   if (_heap_align_base(BLOCK_SIZE) == MALLOC_ERROR) {
  183.     malloc_errno = MALLOC_BAD_SETUP;
  184.     _malloc_perror("_chunk_startup");
  185.     return ERROR;
  186.   }
  187.   
  188.   /* initialize free bins */
  189.   for (binc = 0; binc <= LARGEST_BLOCK; binc++)
  190.     free_bblock[binc] = NULL;
  191.   for (binc = 0; binc < BASIC_BLOCK; binc++)
  192.     free_dblock[binc] = NULL;
  193.   
  194.   /* assign value to add to pointers when displaying */
  195.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  196.     pnt_below_adm = FENCE_BOTTOM;
  197.     pnt_total_adm = FENCE_OVERHEAD;
  198.   }
  199.   else {
  200.     pnt_below_adm = 0;
  201.     pnt_total_adm = 0;
  202.   }
  203.   
  204.   return NOERROR;
  205. }
  206.  
  207. /*
  208.  * return the number of bits in number SIZE
  209.  */
  210. LOCAL    int    num_bits(unsigned int size)
  211. {
  212.   unsigned int    tmp = size;
  213.   int        bitc;
  214.   
  215. #if ALLOW_ALLOC_ZERO_SIZE == 0
  216.   if (size == 0) {
  217.     malloc_errno = MALLOC_BAD_SIZE;
  218.     _malloc_perror("num_bits");
  219.     return ERROR;
  220.   }
  221. #endif
  222.   
  223.   /* shift right until 0, 2 ^ 0 == 1 */
  224.   for (bitc = -1; tmp > 0; bitc++)
  225.     tmp >>= 1;
  226.   
  227.   /* are we not a base 2 number? */
  228.   if (size > (1 << bitc))
  229.     bitc++;
  230.   
  231.   return bitc;
  232. }
  233.  
  234. /*
  235.  * "allocate" another bblock administrative block
  236.  * NOTE: some logistic problems with getting from free list
  237.  */
  238. LOCAL    bblock_adm_t    *get_bblock_admin(void)
  239. {
  240.   bblock_adm_t    *new;
  241.   bblock_t    *bblockp;
  242.   
  243.   bblock_adm_count++;
  244.   bblock_count++;
  245.   
  246.   /* get some more space for a bblock_admin structure */
  247.   new = (bblock_adm_t *)_heap_alloc(BLOCK_SIZE);
  248.   if (new == (bblock_adm_t *)HEAP_ALLOC_ERROR)
  249.     return NULL;
  250.   
  251.   /* do we need to print admin info? */
  252.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  253.     _malloc_message("new bblock admin alloced for another %d admin slots",
  254.             BB_PER_ADMIN);
  255.   
  256.   /*
  257.    * initialize the new bblock_admin block
  258.    */
  259.   new->ba_magic1 = CHUNK_MAGIC_BASE;
  260.   if (bblock_adm_tail == NULL)
  261.     new->ba_count = 0;
  262.   else
  263.     new->ba_count = bblock_adm_tail->ba_count + BB_PER_ADMIN;
  264.   
  265.   /* initialize the bblocks in the bblock_admin */
  266.   for (bblockp = new->ba_block; bblockp < new->ba_block + BB_PER_ADMIN;
  267.        bblockp++)
  268.     bblockp->bb_flags = 0;
  269.   
  270.   new->ba_next = NULL;
  271.   new->ba_magic2 = CHUNK_MAGIC_TOP;
  272.   
  273.   /*
  274.    * continue bblock_admin linked-list
  275.    */
  276.   if (bblock_adm_tail == NULL)
  277.     bblock_adm_head = new;
  278.   else
  279.     bblock_adm_tail->ba_next = new;
  280.   bblock_adm_tail = new;
  281.   
  282.   return new;
  283. }
  284.  
  285. /*
  286.  * get MANY of bblocks, return a pointer to the first one
  287.  */
  288. LOCAL    bblock_t    *get_bblocks(int bitc)
  289. {
  290.   static int    free_slots = 0;        /* free slots in last bb_admin */
  291.   int        newc, mark;
  292.   bblock_adm_t    *bblock_admp;
  293.   bblock_t    *bblockp;
  294.   
  295.   if (bitc < BASIC_BLOCK) {
  296.     malloc_errno = MALLOC_BAD_SIZE;
  297.     _malloc_perror("get_bblocks");
  298.     return NULL;
  299.   }
  300.   
  301.   /* do we need to print admin info? */
  302.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  303.     _malloc_message("need bblocks for %d bytes or %d bits", 1 << bitc, bitc);
  304.   
  305.   /* is there anything on the free list? */
  306.   bblockp = free_bblock[bitc];
  307.   if (bblockp != NULL) {
  308.     free_bblock[bitc] = bblockp->bb_next;
  309.     free_space_count -= 1 << bitc;
  310.     return bblockp;
  311.   }
  312.   
  313.   bblock_count += 1 << (bitc - BASIC_BLOCK);
  314.   
  315.   /* point at first free bblock entry (may be out of range) */
  316.   bblock_admp = bblock_adm_tail;
  317.   mark = BB_PER_ADMIN - free_slots;
  318.   
  319.   /* loop until we have enough slots */
  320.   for (newc = 0; free_slots < 1 << (bitc - BASIC_BLOCK); newc++) {
  321.     if (get_bblock_admin() == NULL)
  322.       return NULL;
  323.     
  324.     /* do we need to move to the next bblock admin? */
  325.     if (mark == BB_PER_ADMIN) {
  326.       if (bblock_admp == NULL)
  327.     bblock_admp = bblock_adm_tail;
  328.       else
  329.     bblock_admp = bblock_admp->ba_next;
  330.       mark = 0;
  331.     }
  332.     
  333.     /* write a bblock entry for the bblock admin */
  334.     bblockp = &bblock_admp->ba_block[mark];
  335.     
  336.     bblockp->bb_flags    = BBLOCK_ADMIN;
  337.     bblockp->bb_count    = bblock_adm_tail->ba_count;
  338.     bblockp->bb_adminp    = bblock_adm_tail;
  339.     
  340.     /* add one to mark to pass by bblock admin header */
  341.     mark++;
  342.     
  343.     /* adjust free_slot count for addition of new bblock admin */
  344.     free_slots += BB_PER_ADMIN - 1;
  345.   }
  346.   
  347.   /* do we need to move to the next bblock admin? */
  348.   if (mark == BB_PER_ADMIN) {
  349.     bblock_admp = bblock_admp->ba_next;
  350.     mark = 0;
  351.   }
  352.   
  353.   /* adjust free_slot count for the allocation */
  354.   free_slots -= 1 << (bitc - BASIC_BLOCK);
  355.   
  356.   return &bblock_admp->ba_block[mark];
  357. }
  358.  
  359. /*
  360.  * get MANY of contiguous dblock administrative slots
  361.  */
  362. LOCAL    dblock_t    *get_dblock_admin(int many)
  363. {
  364.   static int        free_slots = 0;
  365.   static dblock_adm_t    *dblock_admp;
  366.   dblock_t        *dblockp;
  367.   bblock_t        *bblockp;
  368.   
  369.   /* do we need to print admin info? */
  370.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  371.     _malloc_message("need %d dblock slots", many);
  372.   
  373.   /* do we have enough right now */
  374.   if (free_slots >= many) {
  375.     free_slots -= many;
  376.     return &dblock_admp->da_block[DB_PER_ADMIN - (free_slots + many)];
  377.   }
  378.   
  379.   /*
  380.    * allocate a new bblock of dblock admin slots, should use free list
  381.    */
  382.   bblockp = get_bblocks(BASIC_BLOCK);
  383.   if (bblockp == NULL)
  384.     return NULL;
  385.   
  386.   dblock_adm_count++;
  387.   
  388.   /* allocate the block if needed */
  389.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
  390.     dblock_admp = (dblock_adm_t *)bblockp->bb_mem;
  391.   else
  392.     dblock_admp = (dblock_adm_t *)_heap_alloc(BLOCK_SIZE);
  393.   if (dblock_admp == (dblock_adm_t *)HEAP_ALLOC_ERROR)
  394.     return NULL;
  395.   
  396.   bblockp->bb_flags = BBLOCK_DBLOCK_ADMIN;
  397.   bblockp->bb_slotp = dblock_admp;
  398.   
  399.   /* do we need to print admin info? */
  400.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  401.     _malloc_message("opened another %d dblock slots", DB_PER_ADMIN);
  402.   
  403.   dblock_admp->da_magic1 = CHUNK_MAGIC_BASE;
  404.   
  405.   /* initialize the db_slots */
  406.   for (dblockp = dblock_admp->da_block;
  407.        dblockp < dblock_admp->da_block + DB_PER_ADMIN; dblockp++) {
  408.     dblockp->db_bblock = NULL;
  409.     dblockp->db_next = NULL;
  410.   }
  411.   
  412.   dblock_admp->da_magic2 = CHUNK_MAGIC_TOP;
  413.   
  414.   free_slots = DB_PER_ADMIN - many;
  415.   
  416.   return dblock_admp->da_block;
  417. }
  418.  
  419. /*
  420.  * get a dblock of 1<<BITC sized chunks, also asked for the slot memory
  421.  */
  422. LOCAL    char    *get_dblock(int bitc, dblock_t ** admp)
  423. {
  424.   bblock_t    *bblockp;
  425.   dblock_t    *dblockp;
  426.   char        *mem;
  427.   
  428.   /* is there anything on the dblock free list? */
  429.   dblockp = free_dblock[bitc];
  430.   if (dblockp != NULL) {
  431.     free_dblock[bitc] = dblockp->db_next;
  432.     free_space_count -= 1 << bitc;
  433.     
  434.     *admp = dblockp;
  435.     
  436.     /* find pointer to memory chunk */
  437.     mem = dblockp->db_bblock->bb_mem +
  438.       (dblockp - dblockp->db_bblock->bb_dblock) * (1 << bitc);
  439.     
  440.     /* do we need to print admin info? */
  441.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  442.       _malloc_message("found a %d byte dblock entry", 1 << bitc);
  443.     
  444.     return mem;
  445.   }
  446.   
  447.   /* do we need to print admin info? */
  448.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  449.     _malloc_message("need to create a dblock for %dx %d byte blocks",
  450.             1 << (BASIC_BLOCK - bitc), 1 << bitc);
  451.   
  452.   /* get some dblock admin slots */
  453.   dblockp = get_dblock_admin(1 << (BASIC_BLOCK - bitc));
  454.   if (dblockp == NULL)
  455.     return NULL;
  456.   *admp = dblockp;
  457.   
  458.   dblock_count++;
  459.   
  460.   /* get a bblock from free list */
  461.   bblockp = get_bblocks(BASIC_BLOCK);
  462.   if (bblockp == NULL)
  463.     return NULL;
  464.   
  465.   /* allocate the block if needed */
  466.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
  467.     mem = bblockp->bb_mem;
  468.   else {
  469.     mem = _heap_alloc(BLOCK_SIZE);
  470.     if (mem == HEAP_ALLOC_ERROR)
  471.       return NULL;
  472.     bblockp->bb_mem = mem;
  473.   }
  474.   
  475.   /* setup bblock information */
  476.   bblockp->bb_flags    = BBLOCK_DBLOCK;
  477.   bblockp->bb_bitc    = bitc;
  478.   bblockp->bb_dblock    = dblockp;
  479.   
  480.   /* add the rest to the free list (has to be at least 1 other dblock) */
  481.   free_dblock[bitc] = ++dblockp;
  482.   free_space_count += 1 << bitc;
  483.   
  484.   for (; dblockp < *admp + (1 << (BASIC_BLOCK - bitc)) - 1; dblockp++) {
  485.     dblockp->db_next    = dblockp + 1;
  486.     dblockp->db_bblock    = bblockp;
  487.     free_space_count    += 1 << bitc;
  488.   }
  489.   
  490.   if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  491.     (void)memset(mem + (1 << bitc), FREE_CHAR, BLOCK_SIZE - (1 << bitc));
  492.   
  493.   /* last one points to NULL */
  494.   dblockp->db_next    = NULL;
  495.   dblockp->db_bblock    = bblockp;
  496.   
  497.   return mem;
  498. }
  499.  
  500. /*
  501.  * find the bblock entry for PNT, return bblock admin in *BB_ADMIN (if != NULL)
  502.  * and return the block number in BLOCK_NUM (if non NULL)
  503.  */
  504. LOCAL    bblock_t    *find_bblock(char * pnt, int * block_num,
  505.                      bblock_adm_t ** bb_admin)
  506. {
  507.   int        bblockc;
  508.   bblock_adm_t    *bblock_admp;
  509.   
  510.   if (pnt == NULL) {
  511.     malloc_errno = MALLOC_POINTER_NULL;
  512.     return NULL;
  513.   }
  514.   
  515.   /*
  516.    * check validity of the pointer
  517.    */
  518.   if (! IS_IN_HEAP(pnt)) {
  519.     malloc_errno = MALLOC_POINTER_NOT_IN_HEAP;
  520.     return NULL;
  521.   }
  522.   
  523.   /* find which block it is in */
  524.   bblockc = WHICH_BLOCK(pnt);
  525.   
  526.   /* do we need to return the block number */
  527.   if (block_num != NULL)
  528.     *block_num = bblockc;
  529.   
  530.   /* find right bblock admin */
  531.   for (bblock_admp = bblock_adm_head; bblock_admp != NULL;
  532.        bblock_admp = bblock_admp->ba_next) {
  533.     if (bblockc < BB_PER_ADMIN)
  534.       break;
  535.     
  536.     bblockc -= BB_PER_ADMIN;
  537.   }
  538.   
  539.   if (bblock_admp == NULL) {
  540.     malloc_errno = MALLOC_POINTER_NOT_FOUND;
  541.     return NULL;
  542.   }
  543.   
  544.   /* should we return bblock admin info? */
  545.   if (bb_admin != NULL)
  546.     *bb_admin = bblock_admp;
  547.   
  548.   return &bblock_admp->ba_block[bblockc];
  549. }
  550.  
  551. /*
  552.  * log the heap structure plus information on the blocks if necessary
  553.  */
  554. LOCAL    void    log_heap_map(void)
  555. {
  556.   bblock_adm_t    *bblock_admp;
  557.   char        line[BB_PER_ADMIN + 10];
  558.   int        linec, bblockc, bb_adminc;
  559.   
  560.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  561.     _malloc_message("logging heap map information");
  562.   
  563.   _malloc_message("heap-base = %#lx, heap-end = %#lx, size = %ld bytes",
  564.           _heap_base, _heap_last, HEAP_SIZE);
  565.   
  566.   for (bb_adminc = 0, bblock_admp = bblock_adm_head; bblock_admp != NULL;
  567.        bb_adminc++, bblock_admp = bblock_admp->ba_next) {
  568.     linec = 0;
  569.     
  570.     for (bblockc = 0; bblockc < BB_PER_ADMIN; bblockc++) {
  571.       bblock_t    *bblockp = &bblock_admp->ba_block[bblockc];
  572.       
  573.       if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
  574.     line[linec++] = '_';
  575.     continue;
  576.       }
  577.       
  578.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  579.     line[linec++] = 'S';
  580.     continue;
  581.       }
  582.       
  583.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_USER)) {
  584.     line[linec++] = 'U';
  585.     continue;
  586.       }
  587.       
  588.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_ADMIN)) {
  589.     line[linec++] = 'A';
  590.     continue;
  591.       }
  592.       
  593.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  594.     line[linec++] = 'd';
  595.     continue;
  596.       }
  597.       
  598.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK_ADMIN)) {
  599.     line[linec++] = 'a';
  600.     continue;
  601.       }
  602.       
  603.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_FREE)) {
  604.     line[linec++] = 'F';
  605.     continue;
  606.       }
  607.     }
  608.     
  609.     /* dumping a line to the logfile */
  610.     if (linec > 0) {
  611.       line[linec] = NULLC;
  612.       _malloc_message("S%d:%s", bb_adminc, line);
  613.     }
  614.   }
  615.   
  616.   /* if we are not logging blocks then leave */
  617.   if (! BIT_IS_SET(_malloc_debug, DEBUG_LOG_BLOCKS))
  618.     return;
  619.   
  620.   for (bb_adminc = 0, bblock_admp = bblock_adm_head; bblock_admp != NULL;
  621.        bb_adminc++, bblock_admp = bblock_admp->ba_next) {
  622.     
  623.     for (bblockc = 0; bblockc < BB_PER_ADMIN; bblockc++) {
  624.       bblock_t    *bblockp = &bblock_admp->ba_block[bblockc];
  625.       
  626.       if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
  627.     _malloc_message("%d: not-allocated block",
  628.             bb_adminc * BB_PER_ADMIN + bblockc);
  629.     /* quit after the first non-allocated is found */
  630.     break;
  631.       }
  632.       
  633.       if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  634.     _malloc_message("%d: start-of-user block: %d bytes from '%s:%u'",
  635.             bb_adminc * BB_PER_ADMIN + bblockc,
  636.             bblockp->bb_size, bblockp->bb_file, bblockp->bb_line);
  637.     continue;
  638.       }
  639.       
  640.       if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_USER)) {
  641.     _malloc_message("%d: user continuation block",
  642.             bb_adminc * BB_PER_ADMIN + bblockc);
  643.     continue;
  644.       }
  645.       
  646.       if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_ADMIN)) {
  647.     _malloc_message("%d: administration block",
  648.             bb_adminc * BB_PER_ADMIN + bblockc);
  649.     continue;
  650.       }
  651.       
  652.       if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_DBLOCK)) {
  653.     _malloc_message("%d: dblock block",
  654.             bb_adminc * BB_PER_ADMIN + bblockc);
  655.     continue;
  656.       }
  657.       
  658.       if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags,
  659.              BBLOCK_DBLOCK_ADMIN)) {
  660.     _malloc_message("%d: dblock-admin block",
  661.             bb_adminc * BB_PER_ADMIN + bblockc);
  662.     continue;
  663.       }
  664.       
  665.       if (BIT_IS_SET(bblock_admp->ba_block[bblockc].bb_flags, BBLOCK_FREE)) {
  666.     _malloc_message("%d: free block",
  667.             bb_adminc * BB_PER_ADMIN + bblockc);
  668.     continue;
  669.       }
  670.     }
  671.   }
  672. }
  673.  
  674. /*
  675.  * run extensive tests on the entire heap depending on TYPE
  676.  */
  677. EXPORT    int    _chunk_heap_check(void)
  678. {
  679.   bblock_adm_t    *this, *last_admp;
  680.   bblock_t    *bblockp, *bblistp, *last_bblockp;
  681.   dblock_t    *dblockp;
  682.   int        undef = 0, start = 0;
  683.   char        *bytep;
  684.   char        *mem;
  685.   int        bitc, dblockc = 0, bblockc = 0, freec = 0;
  686.   int        bbc = 0, len;
  687.   int        free_bblockc[LARGEST_BLOCK + 1];
  688.   int        free_dblockc[BASIC_BLOCK];
  689.   
  690.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  691.     _malloc_message("checking heap");
  692.   
  693.   /* if the heap is empty then no need to check anything */
  694.   if (bblock_adm_head == NULL)
  695.     return NOERROR;
  696.   
  697.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  698.     
  699.     /* count the bblock free lists */
  700.     for (bitc = 0; bitc < LARGEST_BLOCK + 1; bitc++) {
  701.       free_bblockc[bitc] = 0;
  702.       
  703.       /* parse bblock free list doing minimal pointer checking */
  704.       for (bblockp = free_bblock[bitc]; bblockp != NULL;
  705.        bblockp = bblockp->bb_next, free_bblockc[bitc]++)
  706.     if (bblockp->bb_next != NULL && ! IS_IN_HEAP(bblockp->bb_next)) {
  707.       malloc_errno = MALLOC_BAD_FREE_LIST;
  708.       _malloc_perror("_chunk_heap_check");
  709.       return ERROR;
  710.     }
  711.     }
  712.     
  713.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  714.       
  715.       /* count the dblock free lists */
  716.       for (bitc = 0; bitc < BASIC_BLOCK; bitc++) {
  717.     free_dblockc[bitc] = 0;
  718.     
  719.     /* parse dblock free list doing minimal pointer checking */
  720.     for (dblockp = free_dblock[bitc]; dblockp != NULL;
  721.          dblockp = dblockp->db_next, free_dblockc[bitc]++)
  722.       if (dblockp->db_next != NULL && ! IS_IN_HEAP(dblockp->db_next)) {
  723.         malloc_errno = MALLOC_BAD_FREE_LIST;
  724.         _malloc_perror("_chunk_heap_check");
  725.         return ERROR;
  726.       }
  727.       }
  728.     }
  729.   }
  730.   
  731.   /* start pointers */
  732.   this = bblock_adm_head;
  733.   last_admp = NULL;
  734.   last_bblockp = NULL;
  735.   
  736.   /* test admin pointer validity */
  737.   if (! IS_IN_HEAP(this)) {
  738.     malloc_errno = MALLOC_BAD_ADMINP;
  739.     _malloc_perror("_chunk_heap_check");
  740.     return ERROR;
  741.   }
  742.   
  743.   /* test structure validity */
  744.   if (this->ba_magic1 != CHUNK_MAGIC_BASE
  745.       || this->ba_magic2 != CHUNK_MAGIC_TOP) {
  746.     malloc_errno = MALLOC_BAD_ADMIN_MAGIC;
  747.     _malloc_perror("_chunk_heap_check");
  748.     return ERROR;
  749.   }
  750.   
  751.   /* verify count value */
  752.   if (this->ba_count != bbc) {
  753.     malloc_errno = MALLOC_BAD_ADMIN_COUNT;
  754.     _malloc_perror("_chunk_heap_check");
  755.     return ERROR;
  756.   }
  757.   
  758.   /* check out the basic blocks */
  759.   for (bblockp = this->ba_block;; last_bblockp = bblockp++) {
  760.     
  761.     /* are we at the end of the bb_admin section */
  762.     if (bblockp >= this->ba_block + BB_PER_ADMIN) {
  763.       this = this->ba_next;
  764.       bbc += BB_PER_ADMIN;
  765.       
  766.       /* are we done? */
  767.       if (this == NULL)
  768.     break;
  769.       
  770.       /* test admin pointer validity */
  771.       if (! IS_IN_HEAP(this)) {
  772.     malloc_errno = MALLOC_BAD_ADMINP;
  773.     _malloc_perror("_chunk_heap_check");
  774.     return ERROR;
  775.       }
  776.       
  777.       /* test structure validity */
  778.       if (this->ba_magic1 != CHUNK_MAGIC_BASE
  779.       || this->ba_magic2 != CHUNK_MAGIC_TOP) {
  780.     malloc_errno = MALLOC_BAD_ADMIN_MAGIC;
  781.     _malloc_perror("_chunk_heap_check");
  782.     return ERROR;
  783.       }
  784.       
  785.       /* verify count value */
  786.       if (this->ba_count != bbc) {
  787.     malloc_errno = MALLOC_BAD_ADMIN_COUNT;
  788.     _malloc_perror("_chunk_heap_check");
  789.     return ERROR;
  790.       }
  791.       
  792.       bblockp = this->ba_block;
  793.     }
  794.     
  795.     /* check for no-allocation */
  796.     if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED)) {
  797.       undef = 1;
  798.       continue;
  799.     }
  800.     
  801.     /* we better not have seen a not-allocated block before */
  802.     if (undef == 1) {
  803.       malloc_errno = MALLOC_BAD_BLOCK_ORDER;
  804.       _malloc_perror("_chunk_heap_check");
  805.       return ERROR;
  806.     }
  807.     
  808.     start = 0;
  809.     
  810.     /*
  811.      * check for different types
  812.      */
  813.     switch (bblockp->bb_flags) {
  814.       
  815.       /* check a starting user-block */
  816.     case BBLOCK_START_USER:
  817.       
  818.       /* check X blocks in a row */
  819.       if (bblockc != 0) {
  820.     malloc_errno = MALLOC_USER_NON_CONTIG;
  821.     _malloc_perror("_chunk_heap_check");
  822.     return ERROR;
  823.       }
  824.       
  825.       /* mark the size in bits */
  826.       bitc = num_bits(bblockp->bb_size);
  827.       if (bitc == ERROR)
  828.     return ERROR;
  829.       bblockc = 1 << (bitc - BASIC_BLOCK);
  830.       start = 1;
  831.       
  832.       /* check fence-posts for memory chunk */
  833.       if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  834.     mem = BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block));
  835.     if (fence_read(bblockp->bb_file, bblockp->bb_line,
  836.                mem, bblockp->bb_size) != NOERROR)
  837.       return ERROR;
  838.       }
  839.       
  840.       /* NOTE: NO BREAK HERE ON PURPOSE */
  841.       
  842.     case BBLOCK_USER:
  843.       
  844.       /* check line number */
  845.       if (bblockp->bb_line > MAX_LINE_NUMBER) {
  846.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  847.       _malloc_message("bad line number on pointer alloced in '%s:%u'",
  848.               bblockp->bb_file, bblockp->bb_line);
  849.     malloc_errno = MALLOC_BAD_LINE;
  850.     _malloc_perror("_chunk_heap_check");
  851.     return ERROR;
  852.       }
  853.       
  854.       /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
  855.       if (bblockp->bb_size <= BLOCK_SIZE / 2
  856.       || bblockp->bb_size > (1 << LARGEST_BLOCK)) {
  857.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  858.       _malloc_message("bad size on pointer alloced in '%s:%u'",
  859.               bblockp->bb_file, bblockp->bb_line);
  860.     malloc_errno = MALLOC_BAD_SIZE;
  861.     _malloc_perror("_chunk_heap_check");
  862.     return ERROR;
  863.       }
  864.       
  865.       /* check file pointer */
  866.       if (bblockp->bb_file == NULL) {
  867.     len = strlen(bblockp->bb_file);
  868.     if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  869.       malloc_errno = MALLOC_BAD_FILEP;
  870.       _malloc_perror("_chunk_heap_check");
  871.       return ERROR;
  872.     }
  873.       }
  874.       
  875.       /* check X blocks in a row */
  876.       if (bblockc == 0) {
  877.     malloc_errno = MALLOC_USER_NON_CONTIG;
  878.     _malloc_perror("_chunk_heap_check");
  879.     return ERROR;
  880.       }
  881.       else
  882.     if (start == 0
  883.         && (last_bblockp == NULL
  884.         || (last_bblockp->bb_flags != BBLOCK_START_USER &&
  885.             last_bblockp->bb_flags != BBLOCK_USER)
  886.         || bblockp->bb_file != last_bblockp->bb_file
  887.         || bblockp->bb_line != last_bblockp->bb_line
  888.         || bblockp->bb_size != last_bblockp->bb_size)) {
  889.       malloc_errno = MALLOC_USER_NON_CONTIG;
  890.       _malloc_perror("_chunk_heap_check");
  891.       return ERROR;
  892.     }
  893.       
  894.       bblockc--;
  895.       
  896.       /* NOTE: we should check above the allocated space if alloc_blank on */
  897.       
  898.       break;
  899.       
  900.     case BBLOCK_ADMIN:
  901.       
  902.       /* check the bblock_admin linked-list */
  903.       if ((last_admp == NULL && bblockp->bb_adminp != bblock_adm_head)
  904.       || (last_admp != NULL && last_admp->ba_next != bblockp->bb_adminp)) {
  905.     malloc_errno = MALLOC_BAD_BLOCK_ADMINP;
  906.     _malloc_perror("_chunk_heap_check");
  907.     return ERROR;
  908.       }
  909.       last_admp = bblockp->bb_adminp;
  910.       
  911.       /* check count against admin count */
  912.       if (bblockp->bb_count != bblockp->bb_adminp->ba_count) {
  913.     malloc_errno = MALLOC_BAD_BLOCK_ADMINC;
  914.     _malloc_perror("_chunk_heap_check");
  915.     return ERROR;
  916.       }
  917.       break;
  918.       
  919.     case BBLOCK_DBLOCK:
  920.       
  921.       /* check out bitc */
  922.       if (bblockp->bb_bitc >= BASIC_BLOCK) {
  923.     malloc_errno = MALLOC_BAD_DBLOCK_SIZE;
  924.     _malloc_perror("_chunk_heap_check");
  925.     return ERROR;
  926.       }
  927.       
  928.       /* check out dblock pointer */
  929.       if (! IS_IN_HEAP(bblockp->bb_dblock)) {
  930.     malloc_errno = MALLOC_BAD_DBLOCK_POINTER;
  931.     _malloc_perror("_chunk_heap_check");
  932.     return ERROR;
  933.       }
  934.       
  935.       /* verify mem pointer */
  936.       if (bblockp->bb_mem !=
  937.       BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block))) {
  938.     malloc_errno = MALLOC_BAD_DBLOCK_MEM;
  939.     _malloc_perror("_chunk_heap_check");
  940.     return ERROR;
  941.       }
  942.       
  943.       /* check dblock entry very closely if necessary */
  944.       if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  945.     for (dblockc = 0, dblockp = bblockp->bb_dblock;
  946.          dblockp < bblockp->bb_dblock +
  947.          (1 << (BASIC_BLOCK - bblockp->bb_bitc));
  948.          dblockc++, dblockp++) {
  949.       
  950.       /* check out dblock entry to see if it is not free */
  951.       if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next)) {
  952.         
  953.         if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  954.           dblock_t    *dblistp;
  955.           
  956.           /* find the free block in the free list */
  957.           for (dblistp = free_dblock[bblockp->bb_bitc]; dblistp != NULL;
  958.            dblistp = dblistp->db_next)
  959.         if (dblistp == dblockp)
  960.           break;
  961.           
  962.           /* did we find it? */
  963.           if (dblistp == NULL) {
  964.         malloc_errno = MALLOC_BAD_FREE_LIST;
  965.         _malloc_perror("_chunk_heap_check");
  966.         return ERROR;
  967.           }
  968.           
  969.           free_dblockc[bblockp->bb_bitc]--;
  970.         }
  971.         
  972.         continue;
  973.       }
  974.       
  975.       /*
  976.        * check out size, better be less than BLOCK_SIZE / 2
  977.        * I have to check this twice :-(
  978.        */
  979.       if (dblockp->db_size > BLOCK_SIZE / 2) {
  980.         if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  981.           _malloc_message("bad size on pointer alloced in '%s:%u'",
  982.                   dblockp->db_file, dblockp->db_line);
  983.         malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  984.         _malloc_perror("_chunk_heap_check");
  985.         return ERROR;
  986.       }
  987.       
  988.       if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)
  989.           && BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DB_FENCE)) {
  990.         mem = bblockp->bb_mem + dblockc * (1 << bblockp->bb_bitc);
  991.         if (fence_read(dblockp->db_file, dblockp->db_line,
  992.                mem, dblockp->db_size) != NOERROR)
  993.           return ERROR;
  994.       }
  995.     }
  996.       }
  997.       break;
  998.       
  999.     case BBLOCK_DBLOCK_ADMIN:
  1000.       
  1001.       /* check out dblock pointer */
  1002.       if (! IS_IN_HEAP(bblockp->bb_slotp)) {
  1003.     malloc_errno = MALLOC_BAD_DBADMIN_POINTER;
  1004.     _malloc_perror("_chunk_heap_check");
  1005.     return ERROR;
  1006.       }
  1007.       
  1008.       /* verify magic numbers */
  1009.       if (bblockp->bb_slotp->da_magic1 != CHUNK_MAGIC_BASE
  1010.       || bblockp->bb_slotp->da_magic2 != CHUNK_MAGIC_TOP) {
  1011.     malloc_errno = MALLOC_BAD_DBADMIN_MAGIC;
  1012.     _malloc_perror("_chunk_heap_check");
  1013.     return ERROR;
  1014.       }
  1015.       
  1016.       /* check out each dblock_admin struct? */
  1017.       if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  1018.     for (dblockp = bblockp->bb_slotp->da_block;
  1019.          dblockp < bblockp->bb_slotp->da_block + DB_PER_ADMIN; dblockp++) {
  1020.       
  1021.       /* verify if we have a good bblock pointer and good back pointer */
  1022.       if (dblockp->db_bblock == NULL && dblockp->db_next == NULL)
  1023.         continue;
  1024.       
  1025.       /* check out dblock pointer and next pointer (if free) */
  1026.       if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next)) {
  1027.         
  1028.         /* find pointer to memory chunk */
  1029.         mem = dblockp->db_bblock->bb_mem +
  1030.           (dblockp - dblockp->db_bblock->bb_dblock) *
  1031.         (1 << dblockp->db_bblock->bb_bitc);
  1032.         
  1033.         /* should we verify that we have a block of FREE_CHAR? */
  1034.         if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FREE)
  1035.         && BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1036.           for (bytep = (char *)mem;
  1037.            bytep < (char *)mem + (1 << dblockp->db_bblock->bb_bitc);
  1038.            bytep++)
  1039.         if (*bytep != FREE_CHAR) {
  1040.           if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1041.             _malloc_message("bad free memory at '%#lx'", bytep);
  1042.           malloc_errno = MALLOC_FREE_NON_BLANK;
  1043.           _malloc_perror("_chunk_heap_check");
  1044.           return ERROR;
  1045.         }
  1046.         
  1047.         continue;
  1048.       }
  1049.       
  1050.       /* check out size, better be less than BLOCK_SIZE / 2 */
  1051.       if (dblockp->db_size > BLOCK_SIZE / 2) {
  1052.         if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1053.           _malloc_message("bad size on pointer alloced in '%s:%u'",
  1054.                   dblockp->db_file, dblockp->db_line);
  1055.         malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1056.         _malloc_perror("_chunk_heap_check");
  1057.         return ERROR;
  1058.       }
  1059.       
  1060.       /* check line number */
  1061.       if (dblockp->db_line > MAX_LINE_NUMBER) {
  1062.         if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1063.           _malloc_message("bad line number on pointer alloced in '%s:%u'",
  1064.                   dblockp->db_file, dblockp->db_line);
  1065.         malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1066.         _malloc_perror("_chunk_heap_check");
  1067.         return ERROR;
  1068.       }
  1069.       
  1070.       len = strlen(dblockp->db_file);
  1071.       if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  1072.         malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1073.         _malloc_perror("_chunk_heap_check");
  1074.         return ERROR;
  1075.       }
  1076.     }
  1077.       }
  1078.       break;
  1079.       
  1080.     case BBLOCK_FREE:
  1081.       
  1082.       /* NOTE: check out free_lists, depending on debug value? */
  1083.       
  1084.       /* check out bitc which is the free-lists size */
  1085.       if (bblockp->bb_bitc < BASIC_BLOCK
  1086.       || bblockp->bb_bitc > LARGEST_BLOCK) {
  1087.     malloc_errno = MALLOC_BAD_SIZE;
  1088.     _malloc_perror("_chunk_heap_check");
  1089.     return ERROR;
  1090.       }
  1091.       
  1092.       /* verify linked list pointer */
  1093.       if (bblockp->bb_next != NULL && ! IS_IN_HEAP(bblockp->bb_next)) {
  1094.     malloc_errno = MALLOC_BAD_FREE_LIST;
  1095.     _malloc_perror("_chunk_heap_check");
  1096.     return ERROR;
  1097.       }
  1098.       
  1099.       /* verify mem pointer */
  1100.       if (bblockp->bb_mem !=
  1101.       BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block))) {
  1102.     malloc_errno = MALLOC_BAD_FREE_MEM;
  1103.     _malloc_perror("_chunk_heap_check");
  1104.     return ERROR;
  1105.       }
  1106.       
  1107.       /* check X blocks in a row */
  1108.       if (freec == 0) {
  1109.     freec = 1 << (bblockp->bb_bitc - BASIC_BLOCK);
  1110.     
  1111.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  1112.       
  1113.       /* find the free block in the free list */
  1114.       for (bblistp = free_bblock[bblockp->bb_bitc]; bblistp != NULL;
  1115.            bblistp = bblistp->bb_next)
  1116.         if (bblistp == bblockp)
  1117.           break;
  1118.       
  1119.       /* did we find it? */
  1120.       if (bblistp == NULL) {
  1121.         malloc_errno = MALLOC_BAD_FREE_LIST;
  1122.         _malloc_perror("_chunk_heap_check");
  1123.         return ERROR;
  1124.       }
  1125.       
  1126.       free_bblockc[bblockp->bb_bitc]--;
  1127.     }
  1128.       }
  1129.       else
  1130.     if (last_bblockp == NULL || last_bblockp->bb_flags != BBLOCK_FREE
  1131.         || bblockp->bb_bitc != last_bblockp->bb_bitc) {
  1132.       malloc_errno = MALLOC_FREE_NON_CONTIG;
  1133.       _malloc_perror("_chunk_heap_check");
  1134.       return ERROR;
  1135.     }
  1136.       freec--;
  1137.       
  1138.       /* should we verify that we have a block of FREE_CHAR? */
  1139.       if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FREE)
  1140.       && BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1141.     for (bytep = (char *)bblockp->bb_mem;
  1142.          bytep < (char *)bblockp->bb_mem + BLOCK_SIZE; bytep++)
  1143.       if (*bytep != FREE_CHAR) {
  1144.         if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1145.           _malloc_message("bad free memory at '%#lx'", bytep);
  1146.         malloc_errno = MALLOC_FREE_NON_BLANK;
  1147.         _malloc_perror("_chunk_heap_check");
  1148.         return ERROR;
  1149.       }
  1150.       break;
  1151.       
  1152.     default:
  1153.       malloc_errno = MALLOC_BAD_FLAG;
  1154.       _malloc_perror("_chunk_heap_check");
  1155.       return ERROR;
  1156.       break;
  1157.     }
  1158.   }
  1159.   
  1160.   /*
  1161.    * any left over contiguous counters?
  1162.    */
  1163.   if (bblockc > 0) {
  1164.     malloc_errno = MALLOC_USER_NON_CONTIG;
  1165.     _malloc_perror("_chunk_heap_check");
  1166.     return ERROR;
  1167.   }
  1168.   if (freec > 0) {
  1169.     malloc_errno = MALLOC_FREE_NON_CONTIG;
  1170.     _malloc_perror("_chunk_heap_check");
  1171.     return ERROR;
  1172.   }
  1173.   
  1174.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_LISTS)) {
  1175.     
  1176.     /* any free bblock entries not accounted for? */
  1177.     for (bitc = 0; bitc < LARGEST_BLOCK + 1; bitc++)
  1178.       if (free_bblockc[bitc] != 0) {
  1179.     malloc_errno = MALLOC_BAD_FREE_LIST;
  1180.     _malloc_perror("_chunk_heap_check");
  1181.     return ERROR;
  1182.       }
  1183.     
  1184.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_DBLOCK)) {
  1185.       /* any free dblock entries not accounted for? */
  1186.       for (bitc = 0; bitc < BASIC_BLOCK; bitc++)
  1187.     if (free_dblockc[bitc] != 0) {
  1188.       malloc_errno = MALLOC_BAD_FREE_LIST;
  1189.       _malloc_perror("_chunk_heap_check");
  1190.       return ERROR;
  1191.     }
  1192.     }
  1193.   }
  1194.   
  1195.   if (BIT_IS_SET(_malloc_debug, DEBUG_HEAP_CHECK_MAP))
  1196.     log_heap_map();
  1197.   
  1198.   return NOERROR;
  1199. }
  1200.  
  1201. /*
  1202.  * run extensive tests on PNT from FUNC. test PNT HOW_MUCH of MIN_SIZE
  1203.  * (or 0 if unknown).  returns [NO]ERROR
  1204.  */
  1205. EXPORT    int    _chunk_pnt_check(const char * func, char * pnt,
  1206.                  const int check, int min_size)
  1207. {
  1208.   bblock_t    *bblockp;
  1209.   dblock_t    *dblockp;
  1210.   int        len, diff;
  1211.   
  1212.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  1213.     _malloc_message("checking pointer '%#lx'", pnt);
  1214.   
  1215.   /* adjust the pointer down if fence-posting */
  1216.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  1217.     pnt -= FENCE_BOTTOM;
  1218.     if (min_size != 0)
  1219.       min_size += FENCE_OVERHEAD;
  1220.   }
  1221.   
  1222.   /* find which block it is in */
  1223.   bblockp = find_bblock(pnt, NULL, NULL);
  1224.   if (bblockp == NULL) {
  1225.     if (check == CHUNK_PNT_LOOSE) {
  1226.       /* the pointer might not be the heap or might be NULL */
  1227.       malloc_errno = 0;
  1228.       return NOERROR;
  1229.     }
  1230.     else {
  1231.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1232.     _malloc_message("bad pointer '%#lx'", pnt);
  1233.       _malloc_perror("find_bblock");
  1234.       return ERROR;
  1235.     }
  1236.   }
  1237.   
  1238.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1239.     /* on a mini-block boundary? */
  1240.     diff = (pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc);
  1241.     if (diff != 0) {
  1242.       if (check == CHUNK_PNT_LOOSE) {
  1243.     if (min_size != 0)
  1244.       min_size += diff;
  1245.     pnt -= diff;
  1246.       }
  1247.       else {
  1248.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1249.       _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1250.     malloc_errno = MALLOC_NOT_ON_BLOCK;
  1251.     _malloc_perror(func);
  1252.     return ERROR;
  1253.       }
  1254.     }
  1255.     
  1256.     /* find correct dblockp */
  1257.     dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1258.       (1 << bblockp->bb_bitc);
  1259.     
  1260.     if (dblockp->db_bblock == bblockp) {
  1261.       /* NOTE: we should run through free list here */
  1262.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1263.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1264.       malloc_errno = MALLOC_ALREADY_FREE;
  1265.       _malloc_perror(func);
  1266.       return ERROR;
  1267.     }
  1268.     
  1269.     /* check line number */
  1270.     if (dblockp->db_line > MAX_LINE_NUMBER) {
  1271.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1272.     _malloc_message("bad line number on pointer '%#lx' alloced in '%s:%u'",
  1273.             CHUNK_TO_USER(pnt), dblockp->db_file,
  1274.             dblockp->db_line);
  1275.       malloc_errno = MALLOC_BAD_LINE;
  1276.       _malloc_perror(func);
  1277.       return ERROR;
  1278.     }
  1279.     
  1280.     /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
  1281.     if (dblockp->db_size > BLOCK_SIZE / 2) {
  1282.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1283.     _malloc_message("bad size on pointer '%#lx' alloced in '%s:%u'",
  1284.             CHUNK_TO_USER(pnt), dblockp->db_file,
  1285.             dblockp->db_line);
  1286.       malloc_errno = MALLOC_BAD_DBADMIN_SLOT;
  1287.       _malloc_perror(func);
  1288.       return ERROR;
  1289.     }
  1290.     
  1291.     if (min_size != 0 && dblockp->db_size < min_size) {
  1292.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1293.     _malloc_message("not enough space in pointer '%#lx' alloced in "
  1294.             "'%s:%u'",
  1295.             CHUNK_TO_USER(pnt), dblockp->db_file,
  1296.             dblockp->db_line);
  1297.       malloc_errno = MALLOC_WOULD_OVERWRITE;
  1298.       _malloc_perror(func);
  1299.       return ERROR;
  1300.     }
  1301.     
  1302.     /* check file pointer */
  1303.     if (dblockp->db_file == NULL) {
  1304.       len = strlen(dblockp->db_file);
  1305.       if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  1306.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1307.       _malloc_message("bad file-name on pointer '%#lx' alloced in '%s:%u'",
  1308.               CHUNK_TO_USER(pnt), dblockp->db_file,
  1309.               dblockp->db_line);
  1310.     malloc_errno = MALLOC_BAD_FILEP;
  1311.     _malloc_perror(func);
  1312.     return ERROR;
  1313.       }
  1314.     }
  1315.     
  1316.     /* check out the fence-posts */
  1317.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1318.       if (fence_read(dblockp->db_file, dblockp->db_line,
  1319.              pnt, dblockp->db_size) != NOERROR)
  1320.     return ERROR;
  1321.     
  1322.     return NOERROR;
  1323.   }
  1324.   
  1325.   /* on a block boundary? */
  1326.   if (! ON_BLOCK(pnt)) {
  1327.     if (check == CHUNK_PNT_LOOSE) {
  1328.       /*
  1329.        * normalize size and pointer to nearest block.
  1330.        *
  1331.        * NOTE: we really need to back-track up the block list to find the
  1332.        * starting user block to test things.
  1333.        */
  1334.       diff = pnt - BLOCK_POINTER(WHICH_BLOCK(pnt));
  1335.       pnt -= diff;
  1336.       if (min_size != 0)
  1337.     min_size += diff;
  1338.     }
  1339.     else {
  1340.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1341.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1342.       malloc_errno = MALLOC_NOT_ON_BLOCK;
  1343.       _malloc_perror(func);
  1344.       return ERROR;
  1345.     }
  1346.   }
  1347.   
  1348.   /* are we on a normal block */
  1349.   if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)
  1350.       && ! (check == CHUNK_PNT_LOOSE
  1351.         && BIT_IS_SET(bblockp->bb_flags, BBLOCK_USER))) {
  1352.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1353.       _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1354.     malloc_errno = MALLOC_NOT_START_USER;
  1355.     _malloc_perror(func);
  1356.     return ERROR;
  1357.   }
  1358.   
  1359.   /* check line number */
  1360.   if (bblockp->bb_line > MAX_LINE_NUMBER) {
  1361.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1362.       _malloc_message("bad line number on pointer '%#lx' alloced in '%s:%u'",
  1363.               CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
  1364.     malloc_errno = MALLOC_BAD_LINE;
  1365.     _malloc_perror(func);
  1366.     return ERROR;
  1367.   }
  1368.   
  1369.   /* check out size, BLOCK_SIZE / 2 == 512 when dblock allocs take over */
  1370.   if (bblockp->bb_size <= BLOCK_SIZE / 2
  1371.       || bblockp->bb_size > (1 << LARGEST_BLOCK)) {
  1372.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1373.       _malloc_message("bad size on pointer '%#lx' alloced in '%s:%u'",
  1374.               CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
  1375.     malloc_errno = MALLOC_BAD_SIZE;
  1376.     _malloc_perror(func);
  1377.     return ERROR;
  1378.   }
  1379.   
  1380.   if (min_size != 0 && bblockp->bb_size < min_size) {
  1381.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1382.       _malloc_message("not enough space in pointer '%#lx' alloced in '%s:%u'",
  1383.               CHUNK_TO_USER(pnt), bblockp->bb_file, bblockp->bb_line);
  1384.     malloc_errno = MALLOC_WOULD_OVERWRITE;
  1385.     _malloc_perror(func);
  1386.     return ERROR;
  1387.   }
  1388.   
  1389.   /* check file pointer */
  1390.   if (bblockp->bb_file == NULL) {
  1391.     len = strlen(bblockp->bb_file);
  1392.     if (len < MIN_FILE_LENGTH || len > MAX_FILE_LENGTH) {
  1393.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1394.     _malloc_message("bad file-name on pointer '%#lx' alloced in '%s:%u'",
  1395.             CHUNK_TO_USER(pnt), bblockp->bb_file,
  1396.             bblockp->bb_line);
  1397.       malloc_errno = MALLOC_BAD_FILEP;
  1398.       _malloc_perror(func);
  1399.       return ERROR;
  1400.     }
  1401.   }
  1402.   
  1403.   /* check out the fence-posts if we are at the start of a user-block */
  1404.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)
  1405.       && BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1406.     if (fence_read(bblockp->bb_file, bblockp->bb_line,
  1407.            pnt, bblockp->bb_size) != NOERROR)
  1408.       return ERROR;
  1409.   
  1410.   return NOERROR;
  1411. }
  1412.  
  1413. /**************************** information routines ***************************/
  1414.  
  1415. /*
  1416.  * return some information associated with PNT, returns [NO]ERROR
  1417.  */
  1418. EXPORT    int    _chunk_read_info(char * pnt, unsigned int * size,
  1419.                  char ** file, unsigned int * line)
  1420. {
  1421.   bblock_t    *bblockp;
  1422.   dblock_t    *dblockp;
  1423.   
  1424.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  1425.     _malloc_message("reading info about pointer '%#lx'", pnt);
  1426.   
  1427.   /* adjust the pointer down if fence-posting */
  1428.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1429.     pnt -= FENCE_BOTTOM;
  1430.   
  1431.   /* find which block it is in */
  1432.   bblockp = find_bblock(pnt, NULL, NULL);
  1433.   if (bblockp == NULL) {
  1434.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1435.       _malloc_message("bad pointer '%#lx'", pnt);
  1436.     _malloc_perror("find_bblock");
  1437.     return ERROR;
  1438.   }
  1439.   
  1440.   /* are we looking in a DBLOCK */
  1441.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1442.     /* on a mini-block boundary? */
  1443.     if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
  1444.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1445.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1446.       malloc_errno = MALLOC_NOT_ON_BLOCK;
  1447.       _malloc_perror("_chunk_read_info");
  1448.       return ERROR;
  1449.     }
  1450.     
  1451.     /* find correct dblockp */
  1452.     dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1453.       (1 << bblockp->bb_bitc);
  1454.     
  1455.     if (dblockp->db_bblock == bblockp) {
  1456.       /* NOTE: we should run through free list here */
  1457.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1458.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1459.       malloc_errno = MALLOC_ALREADY_FREE;
  1460.       _malloc_perror("_chunk_read_info");
  1461.       return ERROR;
  1462.     }
  1463.     
  1464.     /* write info back to user space */
  1465.     if (size != NULL)
  1466.       *size = dblockp->db_size;
  1467.     if (file != NULL)
  1468.       *file = dblockp->db_file;
  1469.     if (line != NULL)
  1470.       *line = dblockp->db_line;
  1471.   }
  1472.   else {
  1473.     
  1474.     /* verify that the pointer is either dblock or user allocated */
  1475.     if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  1476.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1477.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1478.       malloc_errno = MALLOC_NOT_USER;
  1479.       _malloc_perror("_chunk_read_info");
  1480.       return ERROR;
  1481.     }
  1482.     
  1483.     /* write info back to user space */
  1484.     if (size != NULL)
  1485.       *size = bblockp->bb_size;
  1486.     if (file != NULL)
  1487.       *file = bblockp->bb_file;
  1488.     if (line != NULL)
  1489.       *line = bblockp->bb_line;
  1490.   }
  1491.   
  1492.   return NOERROR;
  1493. }
  1494.  
  1495. /*
  1496.  * write new FILE, LINE, SIZE info into PNT
  1497.  */
  1498. LOCAL    int    chunk_write_info(const char * file, const unsigned int line,
  1499.                  char * pnt, unsigned int size)
  1500. {
  1501.   int        bitc, bblockc;
  1502.   bblock_t    *bblockp;
  1503.   dblock_t    *dblockp;
  1504.   bblock_adm_t    *bblock_admp;
  1505.   
  1506.   /* find which block it is in */
  1507.   bblockp = find_bblock(pnt, NULL, &bblock_admp);
  1508.   if (bblockp == NULL) {
  1509.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1510.       _malloc_message("bad pointer '%#lx'", pnt);
  1511.     _malloc_perror("find_bblock");
  1512.     return ERROR;
  1513.   }
  1514.   
  1515.   /* are we looking in a DBLOCK */
  1516.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1517.     /* on a mini-block boundary? */
  1518.     if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
  1519.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1520.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1521.       malloc_errno = MALLOC_NOT_ON_BLOCK;
  1522.       _malloc_perror("chunk_write_info");
  1523.       return ERROR;
  1524.     }
  1525.     
  1526.     /* find correct dblockp */
  1527.     dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1528.       (1 << bblockp->bb_bitc);
  1529.     
  1530.     if (dblockp->db_bblock == bblockp) {
  1531.       /* NOTE: we should run through free list here */
  1532.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1533.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1534.       malloc_errno = MALLOC_NOT_USER;
  1535.       _malloc_perror("chunk_write_info");
  1536.       return ERROR;
  1537.     }
  1538.     
  1539.     /* write info back to user space */
  1540.     if (size != NULL)
  1541.       dblockp->db_size = size;
  1542.     if (file != NULL)
  1543.       dblockp->db_file = (char *)file;
  1544.     if (line != NULL)
  1545.       dblockp->db_line = (unsigned short)line;
  1546.   }
  1547.   else {
  1548.     
  1549.     /* verify that the pointer is user allocated */
  1550.     if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  1551.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1552.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1553.       malloc_errno = MALLOC_NOT_USER;
  1554.       _malloc_perror("chunk_write_info");
  1555.       return ERROR;
  1556.     }
  1557.     
  1558.     /* count the bits */
  1559.     bitc = num_bits(bblockp->bb_size);
  1560.     if (bitc == ERROR)
  1561.       return ERROR;
  1562.     if (bitc < BASIC_BLOCK) {
  1563.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1564.     _malloc_message("bad size on pointer '%#lx'", CHUNK_TO_USER(pnt));
  1565.       malloc_errno = MALLOC_BAD_SIZE_INFO;
  1566.       _malloc_perror("chunk_write_info");
  1567.       return ERROR;
  1568.     }
  1569.     
  1570.     /*
  1571.      * reset values in the bblocks
  1572.      */
  1573.     for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
  1574.      bblockc++, bblockp++) {
  1575.       
  1576.       /* do we need to hop to a new bblock_admp header? */
  1577.       if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
  1578.     bblock_admp = bblock_admp->ba_next;
  1579.     if (bblock_admp == NULL) {
  1580.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1581.         _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1582.       malloc_errno = MALLOC_BAD_ADMIN_LIST;
  1583.       _malloc_perror("chunk_write_info");
  1584.       return ERROR;
  1585.     }
  1586.     bblockp = bblock_admp->ba_block;
  1587.       }
  1588.       
  1589.       /* set bblock info */
  1590.       bblockp->bb_size = size;
  1591.       bblockp->bb_file = (char *)file;
  1592.       bblockp->bb_line = (unsigned short)line;
  1593.     }
  1594.   }
  1595.   
  1596.   return NOERROR;
  1597. }
  1598.  
  1599. /************************** low-level user functions *************************/
  1600.  
  1601. /*
  1602.  * get a SIZE chunk of memory for FILE at LINE
  1603.  */
  1604. EXPORT    char    *_chunk_malloc(const char * file, const unsigned int line,
  1605.                    unsigned int size)
  1606. {
  1607.   int        bitc, bblockc;
  1608.   bblock_t    *bblockp;
  1609.   bblock_adm_t    *bblock_admp;
  1610.   dblock_t    *dblockp;
  1611.   char        *mem;
  1612.   
  1613.   malloc_count++;                /* counts calls to malloc */
  1614.   
  1615. #if ALLOW_ALLOC_ZERO_SIZE == 0
  1616.   if (size == 0) {
  1617.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1618.       _malloc_message("bad zero byte allocation from '%s:%u'", file, line);
  1619.     malloc_errno = MALLOC_BAD_SIZE;
  1620.     _malloc_perror("_chunk_malloc");
  1621.     return MALLOC_ERROR;
  1622.   }
  1623. #endif
  1624.   
  1625.   if (file == NULL) {
  1626.     malloc_errno = MALLOC_BAD_FILEP;
  1627.     _malloc_perror("_chunk_malloc");
  1628.     return MALLOC_ERROR;
  1629.   }
  1630.   
  1631.   /* adjust the size */
  1632.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1633.     size += FENCE_OVERHEAD;
  1634.   
  1635.   /* count the bits */
  1636.   bitc = num_bits(size);
  1637.   if (bitc == ERROR)
  1638.     return MALLOC_ERROR;
  1639.   
  1640.   /* monitor current allocation level */
  1641.   alloc_current += size;
  1642.   alloc_cur_given += 1 << bitc;
  1643.   alloc_maximum = MAX(alloc_maximum, alloc_current);
  1644.   alloc_max_given = MAX(alloc_max_given, alloc_cur_given);
  1645.   alloc_total += size;
  1646.   alloc_one_max = MAX(alloc_one_max, size);
  1647.   
  1648.   /* monitor pointer usage */
  1649.   alloc_cur_pnts++;
  1650.   alloc_max_pnts = MAX(alloc_max_pnts, alloc_cur_pnts);
  1651.   alloc_tot_pnts++;
  1652.   
  1653.   /* have we exceeded the upper bounds */
  1654.   if (bitc > LARGEST_BLOCK) {
  1655.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1656.       _malloc_message("bad allocation of '%d' bytes from '%s:%u'",
  1657.               size, file, line);
  1658.     malloc_errno = MALLOC_TOO_BIG;
  1659.     _malloc_perror("_chunk_malloc");
  1660.     return MALLOC_ERROR;
  1661.   }
  1662.   
  1663.   /* normalize to SMALLEST_BLOCK.  No use spending 16 bytes to admin 1 byte */
  1664.   if (bitc < SMALLEST_BLOCK)
  1665.     bitc = SMALLEST_BLOCK;
  1666.   
  1667.   /* allocate divided block if small */
  1668.   if (bitc < BASIC_BLOCK) {
  1669.     mem = get_dblock(bitc, &dblockp);
  1670.     if (mem == NULL)
  1671.       return MALLOC_ERROR;
  1672.     
  1673.     dblockp->db_line = (unsigned short)line;
  1674.     dblockp->db_size = (unsigned short)size;
  1675.     dblockp->db_file = (char *)file;
  1676.   }
  1677.   else {
  1678.     
  1679.     /*
  1680.      * allocate some bblock space
  1681.      */
  1682.     
  1683.     /* handle blocks */
  1684.     bblockp = get_bblocks(bitc);
  1685.     if (bblockp == NULL)
  1686.       return MALLOC_ERROR;
  1687.     
  1688.     /* calculate current bblock admin pointer and memory pointer */
  1689.     bblock_admp = (bblock_adm_t *)WHAT_BLOCK(bblockp);
  1690.     mem = BLOCK_POINTER(bblock_admp->ba_count +
  1691.             (bblockp - bblock_admp->ba_block));
  1692.     
  1693.     /*
  1694.      * initialize the bblocks
  1695.      */
  1696.     for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
  1697.      bblockc++, bblockp++) {
  1698.       
  1699.       /* do we need to hop to a new bblock admin header? */
  1700.       if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
  1701.     bblock_admp = bblock_admp->ba_next;
  1702.     if (bblock_admp == NULL)
  1703.       return MALLOC_ERROR;
  1704.     
  1705.     bblockp = bblock_admp->ba_block;
  1706.       }
  1707.       
  1708.       /* allocate the block if needed */
  1709.       if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_ALLOCATED))
  1710.     if (_heap_alloc(BLOCK_SIZE) == HEAP_ALLOC_ERROR)
  1711.       return MALLOC_ERROR;
  1712.       
  1713.       if (bblockc == 0)
  1714.     bblockp->bb_flags = BBLOCK_START_USER;
  1715.       else
  1716.     bblockp->bb_flags = BBLOCK_USER;
  1717.       
  1718.       bblockp->bb_line    = (unsigned short)line;
  1719.       bblockp->bb_size    = (unsigned int)size;
  1720.       bblockp->bb_file    = (char *)file;
  1721.     }
  1722.   }
  1723.   
  1724.   /* overwrite to-be-alloced or non-used portion of memory */
  1725.   if (BIT_IS_SET(_malloc_debug, DEBUG_ALLOC_BLANK))
  1726.     (void)memset(mem, FREE_CHAR, 1 << bitc);
  1727.   
  1728.   /* write fence post info if needed */
  1729.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1730.     fence_write(mem, size);
  1731.   
  1732.   /* do we need to print transaction info? */
  1733.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  1734.     _malloc_message("*** alloc: at '%s:%u' asking %u bytes (%d bits), "
  1735.             "got '%#lx'",
  1736.             file, line, size - pnt_total_adm, bitc,
  1737.             mem + pnt_below_adm);
  1738.   
  1739.   return mem + pnt_below_adm;
  1740. }
  1741.  
  1742. /*
  1743.  * frees PNT from the heap, returns FREE_ERROR or FREE_NOERROR
  1744.  */
  1745. EXPORT    int    _chunk_free(const char * file, const unsigned int line,
  1746.                 char * pnt)
  1747. {
  1748.   int        bblockc, bitc;
  1749.   bblock_t    *bblockp, *first;
  1750.   bblock_adm_t    *bblock_admp;
  1751.   dblock_t    *dblockp;
  1752.   
  1753.   free_count++;                    /* counts calls to free */
  1754.   
  1755.   alloc_cur_pnts--;
  1756.   
  1757.   /* adjust the pointer down if fence-posting */
  1758.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1759.     pnt -= FENCE_BOTTOM;
  1760.   
  1761.   /* find which block it is in */
  1762.   bblockp = find_bblock(pnt, NULL, &bblock_admp);
  1763.   if (bblockp == NULL) {
  1764.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1765.       _malloc_message("bad pointer '%#lx'", pnt);
  1766.     _malloc_perror("find_bblock");
  1767.     return FREE_ERROR;
  1768.   }
  1769.   
  1770.   /* are we free'ing a dblock entry? */
  1771.   if (BIT_IS_SET(bblockp->bb_flags, BBLOCK_DBLOCK)) {
  1772.     
  1773.     /* on a mini-block boundary? */
  1774.     if ((pnt - bblockp->bb_mem) % (1 << bblockp->bb_bitc) != 0) {
  1775.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1776.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1777.       malloc_errno = MALLOC_NOT_ON_BLOCK;
  1778.       _malloc_perror("_chunk_free");
  1779.       return FREE_ERROR;
  1780.     }
  1781.     
  1782.     /* find correct dblockp */
  1783.     dblockp = bblockp->bb_dblock + (pnt - bblockp->bb_mem) /
  1784.       (1 << bblockp->bb_bitc);
  1785.     
  1786.     if (dblockp->db_bblock == bblockp) {
  1787.       /* NOTE: we should run through free list here */
  1788.       if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1789.     _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1790.       malloc_errno = MALLOC_ALREADY_FREE;
  1791.       _malloc_perror("_chunk_free");
  1792.       return FREE_ERROR;
  1793.     }
  1794.     
  1795.     /* do we need to print transaction info? */
  1796.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  1797.       _malloc_message("*** free: at '%s:%u' dblock pnter '%#lx': size %u, "
  1798.               "file '%s:%u'",
  1799.               file, line, CHUNK_TO_USER(pnt),
  1800.               dblockp->db_size - pnt_total_adm,
  1801.               dblockp->db_file, dblockp->db_line);
  1802.     
  1803.     /* check fence-post, probably again */
  1804.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1805.       if (fence_read(dblockp->db_file, dblockp->db_line,
  1806.              pnt, dblockp->db_size) != NOERROR)
  1807.     return FREE_ERROR;
  1808.     
  1809.     /* count the bits */
  1810.     bitc = bblockp->bb_bitc;
  1811.     
  1812.     /* monitor current allocation level */
  1813.     alloc_current -= dblockp->db_size;
  1814.     alloc_cur_given -= 1 << bitc;
  1815.     
  1816.     /* rearrange info */
  1817.     dblockp->db_bblock    = bblockp;
  1818.     dblockp->db_next    = free_dblock[bitc];
  1819.     free_dblock[bitc]    = dblockp;
  1820.     free_space_count    += 1 << bitc;
  1821.     
  1822.     /* should we set free memory with FREE_CHAR? */
  1823.     if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1824.       (void)memset(pnt, FREE_CHAR, 1 << bitc);
  1825.     
  1826.     return FREE_NOERROR;
  1827.   }
  1828.   
  1829.   /* on a block boundary? */
  1830.   if (! ON_BLOCK(pnt)) {
  1831.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1832.       _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1833.     malloc_errno = MALLOC_NOT_ON_BLOCK;
  1834.     _malloc_perror("_chunk_free");
  1835.     return FREE_ERROR;
  1836.   }
  1837.   
  1838.   /* are we on a normal block */
  1839.   if (! BIT_IS_SET(bblockp->bb_flags, BBLOCK_START_USER)) {
  1840.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1841.       _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1842.     malloc_errno = MALLOC_NOT_START_USER;
  1843.     _malloc_perror("_chunk_free");
  1844.     return FREE_ERROR;
  1845.   }
  1846.   
  1847.   /* do we need to print transaction info? */
  1848.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  1849.     _malloc_message("*** free: at '%s:%u' bblock pnter '%#lx': size %u, "
  1850.             "file '%s:%u'",
  1851.             file, line, CHUNK_TO_USER(pnt),
  1852.             bblockp->bb_size - pnt_total_adm,
  1853.             bblockp->bb_file, bblockp->bb_line);
  1854.   
  1855.   /* check fence-post, probably again */
  1856.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1857.     if (fence_read(bblockp->bb_file, bblockp->bb_line,
  1858.            pnt, bblockp->bb_size) != NOERROR)
  1859.       return FREE_ERROR;
  1860.   
  1861.   /* count the bits */
  1862.   bitc = num_bits(bblockp->bb_size);
  1863.   if (bitc == ERROR)
  1864.     return FREE_ERROR;
  1865.   
  1866.   /* monitor current allocation level */
  1867.   alloc_current -= bblockp->bb_size;
  1868.   alloc_cur_given -= 1 << bitc;
  1869.   
  1870.   if (bitc < BASIC_BLOCK) {
  1871.     if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_BAD_POINTER))
  1872.       _malloc_message("bad pointer '%#lx'", CHUNK_TO_USER(pnt));
  1873.     malloc_errno = MALLOC_BAD_SIZE_INFO;
  1874.     _malloc_perror("_chunk_free");
  1875.     return FREE_ERROR;
  1876.   }
  1877.   
  1878.   /* setup free linked-list */
  1879.   first = free_bblock[bitc];
  1880.   free_bblock[bitc] = bblockp;
  1881.   free_space_count += 1 << bitc;
  1882.   
  1883.   bblockp->bb_next = first;
  1884.   
  1885.   /*
  1886.    * initialize the bblocks
  1887.    */
  1888.   for (bblockc = 0; bblockc < (1 << (bitc - BASIC_BLOCK));
  1889.        bblockc++, bblockp++, pnt += BLOCK_SIZE) {
  1890.     
  1891.     /* do we need to hop to a new bblock_admp header? */
  1892.     if (bblockp == &bblock_admp->ba_block[BB_PER_ADMIN]) {
  1893.       bblock_admp = bblock_admp->ba_next;
  1894.       if (bblock_admp == NULL) {
  1895.     malloc_errno = MALLOC_BAD_ADMIN_LIST;
  1896.     _malloc_perror("_chunk_free");
  1897.     return FREE_ERROR;
  1898.       }
  1899.       bblockp = bblock_admp->ba_block;
  1900.     }
  1901.     
  1902.     /* set bblock info */
  1903.     bblockp->bb_flags    = BBLOCK_FREE;
  1904.     bblockp->bb_bitc    = bitc;            /* num bblocks in this chunk */
  1905.     bblockp->bb_mem    = pnt;            /* pointer to real memory */
  1906.     bblockp->bb_next    = first;
  1907.     
  1908.     /* should we set free memory with FREE_CHAR? */
  1909.     if (BIT_IS_SET(_malloc_debug, DEBUG_FREE_BLANK))
  1910.       (void)memset(pnt, FREE_CHAR, BLOCK_SIZE);
  1911.   }
  1912.   
  1913.   return FREE_NOERROR;
  1914. }
  1915.  
  1916. /*
  1917.  * reallocate a section of memory
  1918.  */
  1919. EXPORT    char    *_chunk_realloc(const char * file, const unsigned int line,
  1920.                 char * oldp, unsigned int new_size)
  1921. {
  1922.   char        *newp, *old_file;
  1923.   unsigned int    old_size, size, old_line;
  1924.   int        old_bitc, new_bitc;
  1925.   
  1926.   realloc_count++;                /* counts calls to realloc */
  1927.   
  1928.   /* get info about old pointer */
  1929.   if (_chunk_read_info(oldp, &old_size, &old_file, &old_line) != NOERROR)
  1930.     return REALLOC_ERROR;
  1931.   
  1932.   /* adjust the pointer down if fence-posting */
  1933.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  1934.     oldp -= FENCE_BOTTOM;
  1935.     new_size += FENCE_OVERHEAD;
  1936.   }
  1937.   
  1938.   /* check the fence-posting */
  1939.   if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE))
  1940.     if (fence_read(file, line, oldp, old_size) != NOERROR)
  1941.       return REALLOC_ERROR;
  1942.   
  1943.   /* get the old and new bit sizes */
  1944.   old_bitc = num_bits(old_size);
  1945.   if (old_bitc == ERROR)
  1946.     return REALLOC_ERROR;
  1947.   
  1948.   new_bitc = num_bits(new_size);
  1949.   if (new_bitc == ERROR)
  1950.     return REALLOC_ERROR;
  1951.   
  1952.   /* if we are not realloc copying and the size is the same */
  1953.   if (BIT_IS_SET(_malloc_debug, DEBUG_REALLOC_COPY) || old_bitc != new_bitc) {
  1954.     
  1955.     /* readjust info */
  1956.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  1957.       oldp += FENCE_BOTTOM;
  1958.       old_size -= FENCE_OVERHEAD;
  1959.       new_size -= FENCE_OVERHEAD;
  1960.     }
  1961.     
  1962.     /* allocate space for new chunk */
  1963.     newp = _chunk_malloc(file, line, new_size);
  1964.     if (newp == MALLOC_ERROR)
  1965.       return REALLOC_ERROR;
  1966.     
  1967.     /*
  1968.      * NOTE: _chunk_malloc() already took care of the fence stuff...
  1969.      */
  1970.     
  1971.     /* copy stuff into new section of memory */
  1972.     size = MIN(new_size, old_size);
  1973.     if (size > 0)
  1974.       bcopy(oldp, newp, size);
  1975.     
  1976.     /* free old pointer */
  1977.     if (_chunk_free(file, line, oldp) != FREE_NOERROR)
  1978.       return REALLOC_ERROR;
  1979.   }
  1980.   else {
  1981.     /* monitor current allocation level */
  1982.     alloc_current += new_size - old_size;
  1983.     alloc_maximum = MAX(alloc_maximum, alloc_current);
  1984.     alloc_total += new_size;
  1985.     alloc_one_max = MAX(alloc_one_max, new_size);
  1986.     
  1987.     /* monitor pointer usage */
  1988.     alloc_tot_pnts++;
  1989.     
  1990.     /* reuse the old-pointer */
  1991.     newp = oldp;
  1992.     
  1993.     /* rewrite size information */
  1994.     if (chunk_write_info(file, line, newp, new_size) != NOERROR)
  1995.       return REALLOC_ERROR;
  1996.     
  1997.     /* overwrite to-be-alloced or non-used portion of memory */
  1998.     if (BIT_IS_SET(_malloc_debug, DEBUG_ALLOC_BLANK)
  1999.     && (1 << new_bitc) - old_size > 0)
  2000.       (void)memset(newp + old_size, FREE_CHAR, (1 << new_bitc) - old_size);
  2001.     
  2002.     /* write in fence-post info and adjust new pointer over fence info */
  2003.     if (BIT_IS_SET(_malloc_debug, DEBUG_CHECK_FENCE)) {
  2004.       fence_write(newp, new_size);
  2005.       
  2006.       newp += FENCE_BOTTOM;
  2007.       oldp += FENCE_BOTTOM;
  2008.       old_size -= FENCE_OVERHEAD;
  2009.       new_size -= FENCE_OVERHEAD;
  2010.     }
  2011.   }
  2012.   
  2013.   /*
  2014.    * do we need to print transaction info?
  2015.    *
  2016.    * NOTE: pointers and sizes here a user-level real
  2017.    */
  2018.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_TRANS))
  2019.     _malloc_message("*** realloc: at '%s:%u' from '%#lx' (%u bytes) "
  2020.             "file '%s:%u' to '%#lx' (%u bytes)",
  2021.             file, line,
  2022.             oldp, old_size, old_file, old_line,
  2023.             newp, new_size);
  2024.   
  2025.   /* newp is already user-level real */
  2026.   return newp;
  2027. }
  2028.  
  2029. /***************************** diagnostic routines ***************************/
  2030.  
  2031. /*
  2032.  * log present free and used lists
  2033.  */
  2034. EXPORT    void    _chunk_list_count(void)
  2035. {
  2036.   int        bitc, count;
  2037.   char        info[256], tmp[80];
  2038.   bblock_t    *bblockp;
  2039.   dblock_t    *dblockp;
  2040.   
  2041.   /* print header bit-counts */
  2042.   info[0] = NULLC;
  2043.   for (bitc = SMALLEST_BLOCK; bitc <= LARGEST_BLOCK; bitc++) {
  2044.     (void)sprintf(tmp, "%*d", FREE_COLUMN, bitc);
  2045.     (void)strcat(info, tmp);
  2046.   }
  2047.   
  2048.   _malloc_message("bits: %s", info);
  2049.   
  2050.   /* dump the free (and later used) list counts */
  2051.   info[0] = NULLC;
  2052.   for (bitc = SMALLEST_BLOCK; bitc <= LARGEST_BLOCK; bitc++) {
  2053.     if (bitc < BASIC_BLOCK)
  2054.       for (count = 0, dblockp = free_dblock[bitc]; dblockp != NULL;
  2055.        count++, dblockp = dblockp->db_next);
  2056.     else
  2057.       for (count = 0, bblockp = free_bblock[bitc]; bblockp != NULL;
  2058.        count++, bblockp = bblockp->bb_next);
  2059.     
  2060.     (void)sprintf(tmp, "%*d", FREE_COLUMN, count);
  2061.     (void)strcat(info, tmp);
  2062.   }
  2063.   
  2064.   _malloc_message("free: %s", info);
  2065. }
  2066.  
  2067. /*
  2068.  * log statistics on the heap
  2069.  */
  2070. EXPORT    void    _chunk_stats(void)
  2071. {
  2072.   long        overhead;
  2073.   
  2074.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  2075.     _malloc_message("getting chunk statistics");
  2076.   
  2077.   /* version information */
  2078.   _malloc_message("malloc version '%s'", malloc_version);
  2079.   
  2080.   /* general heap information */
  2081.   _malloc_message("heap start %#lx, heap end %#lx, heap size %ld bytes",
  2082.           _heap_base, _heap_last, HEAP_SIZE);
  2083.   
  2084.   /* log user allocation information */
  2085.   _malloc_message("alloc calls: malloc %d, realloc %d, calloc %d, free %d",
  2086.           malloc_count - _calloc_count, realloc_count, _calloc_count,
  2087.           free_count);
  2088.   
  2089.   _malloc_message("total amount of memory allocated:   %ld bytes (%ld pnts)",
  2090.           alloc_total, alloc_tot_pnts);
  2091.   
  2092.   _malloc_message("maximum memory in use at one time:  %ld bytes (%ld pnts)",
  2093.           alloc_maximum, alloc_max_pnts);
  2094.   
  2095.   _malloc_message("maximum memory alloced with 1 call: %ld bytes",
  2096.           alloc_one_max);
  2097.   
  2098.   _malloc_message("max base 2 allocation loss: %ld bytes (%d%%)",
  2099.           alloc_max_given - alloc_maximum,
  2100.           (alloc_max_given == 0 ? 0 :
  2101.            100 - ((alloc_maximum * 100) / alloc_max_given)));
  2102.   
  2103.   _malloc_message("final user memory space: %ld bytes",
  2104.           alloc_current + free_space_count);
  2105.   
  2106.   /* log administration information */
  2107.   _malloc_message("final admin: basic-blocks %d, divided blocks %d",
  2108.           bblock_count, dblock_count);
  2109.   
  2110.   overhead = HEAP_SIZE - (alloc_current + free_space_count);
  2111.   
  2112.   _malloc_message("final heap admin overhead: %ld bytes (%d%%)",
  2113.           overhead,
  2114.           (HEAP_SIZE == 0 ? 0 : (overhead * 100) / HEAP_SIZE));
  2115. }
  2116.  
  2117. /*
  2118.  * dump the unfreed memory, logs the unfreed information to logger
  2119.  */
  2120. EXPORT    void    _chunk_dump_not_freed(void)
  2121. {
  2122.   bblock_adm_t    *this;
  2123.   bblock_t    *bblockp;
  2124.   dblock_t    *dblockp;
  2125.   char        *mem, unknown;
  2126.   int        unknown_sizec = 0, unknown_dblockc = 0, unknown_bblockc = 0;
  2127.   int        sizec = 0, dblockc = 0, bblockc = 0;
  2128.   
  2129.   if (BIT_IS_SET(_malloc_debug, DEBUG_LOG_ADMIN))
  2130.     _malloc_message("dumping the unfreed pointers");
  2131.   
  2132.   /* has anything been alloced yet? */
  2133.   this = bblock_adm_head;
  2134.   if (this == NULL)
  2135.     return;
  2136.   
  2137.   /* check out the basic blocks */
  2138.   for (bblockp = this->ba_block;; bblockp++) {
  2139.     
  2140.     /* are we at the end of the bb_admin section */
  2141.     if (bblockp >= this->ba_block + BB_PER_ADMIN) {
  2142.       this = this->ba_next;
  2143.       
  2144.       /* are we done? */
  2145.       if (this == NULL)
  2146.     break;
  2147.       
  2148.       bblockp = this->ba_block;
  2149.     }
  2150.     
  2151.     /*
  2152.      * check for different types
  2153.      */
  2154.     switch (bblockp->bb_flags) {
  2155.       
  2156.     case BBLOCK_ADMIN:
  2157.     case BBLOCK_DBLOCK:
  2158.     case BBLOCK_FREE:
  2159.     case BBLOCK_USER:
  2160.       break;
  2161.       
  2162.     case BBLOCK_START_USER:
  2163.       /* find pointer to memory chunk */
  2164.       mem = BLOCK_POINTER(this->ba_count + (bblockp - this->ba_block));
  2165.       
  2166.       /* unknown pointer? */
  2167.       if (bblockp->bb_line == MALLOC_DEFAULT_LINE
  2168.       && strcmp(MALLOC_DEFAULT_FILE, bblockp->bb_file) == 0) {
  2169.     unknown_bblockc++;
  2170.     unknown_sizec += bblockp->bb_size - pnt_total_adm;
  2171.     unknown = 1;
  2172.       }
  2173.       else
  2174.     unknown = 0;
  2175.       
  2176.       if (! unknown || BIT_IS_SET(_malloc_debug, DEBUG_LOG_UNKNOWN))
  2177.     _malloc_message("not freed: %#9lx (%8d bytes) from '%s:%u'",
  2178.             mem  + pnt_below_adm, bblockp->bb_size - pnt_total_adm,
  2179.             bblockp->bb_file, bblockp->bb_line);
  2180.       
  2181.       sizec += bblockp->bb_size - pnt_total_adm;
  2182.       bblockc++;
  2183.       break;
  2184.       
  2185.     case BBLOCK_DBLOCK_ADMIN:
  2186.       
  2187.       for (dblockp = bblockp->bb_slotp->da_block;
  2188.        dblockp < bblockp->bb_slotp->da_block + DB_PER_ADMIN; dblockp++) {
  2189.     
  2190.     /* verify if we have a good bblock pointer and good back pointer */
  2191.     if (dblockp->db_bblock == NULL && dblockp->db_next == NULL)
  2192.       continue;
  2193.     
  2194.     /* check out dblock pointer and next pointer (if free) */
  2195.     if (dblockp->db_next == NULL || IS_IN_HEAP(dblockp->db_next))
  2196.       continue;
  2197.     
  2198.     {
  2199.       bblock_adm_t    *bbap;
  2200.       bblock_t    *bbp;
  2201.       
  2202.       bbap = bblock_adm_head;
  2203.       
  2204.       /* check out the basic blocks */
  2205.       for (bbp = bbap->ba_block;; bbp++) {
  2206.         
  2207.         /* are we at the end of the bb_admin section */
  2208.         if (bbp >= bbap->ba_block + BB_PER_ADMIN) {
  2209.           bbap = bbap->ba_next;
  2210.           
  2211.           /* are we done? */
  2212.           if (bbap == NULL)
  2213.         break;
  2214.           
  2215.           bbp = bbap->ba_block;
  2216.         }
  2217.         
  2218.         if (bbp->bb_flags != BBLOCK_DBLOCK)
  2219.           continue;
  2220.         
  2221.         if (dblockp >= bbp->bb_dblock
  2222.         && dblockp < bbp->bb_dblock +
  2223.         (1 << (BASIC_BLOCK - bbp->bb_bitc)))
  2224.           break;
  2225.       }
  2226.       
  2227.       if (bbap == NULL) {
  2228.         malloc_errno = MALLOC_BAD_DBLOCK_POINTER;
  2229.         _malloc_perror("_chunk_dump_not_freed");
  2230.         return;
  2231.       }
  2232.       
  2233.       mem = bbp->bb_mem + (dblockp - bbp->bb_dblock) * (1 << bbp->bb_bitc);
  2234.     }
  2235.     
  2236.     /* unknown pointer? */
  2237.     if (dblockp->db_line == MALLOC_DEFAULT_LINE
  2238.         && strcmp(MALLOC_DEFAULT_FILE, dblockp->db_file) == 0) {
  2239.       unknown_dblockc++;
  2240.       unknown_sizec += dblockp->db_size - pnt_total_adm;
  2241.       unknown = 1;
  2242.     }
  2243.     else
  2244.       unknown = 0;
  2245.     
  2246.     if (! unknown || BIT_IS_SET(_malloc_debug, DEBUG_LOG_UNKNOWN))
  2247.       _malloc_message("not freed: %#9lx (%8d bytes) from '%s:%u'",
  2248.               mem  + pnt_below_adm,
  2249.               dblockp->db_size - pnt_total_adm,
  2250.               dblockp->db_file, dblockp->db_line);
  2251.     
  2252.     sizec += dblockp->db_size - pnt_total_adm;
  2253.     dblockc++;
  2254.       }
  2255.       break;
  2256.     }
  2257.   }
  2258.   
  2259.   /* copy out size of pointers */
  2260.   if (bblockc + dblockc > 0) {
  2261.     _malloc_message("known memory not freed: %d bblock, %d dblock, %d byte%s",
  2262.             bblockc - unknown_bblockc, dblockc - unknown_dblockc,
  2263.             sizec - unknown_sizec, (sizec == 1 ? "" : "s"));
  2264.     
  2265.     _malloc_message("unknown memory not freed: %d bblock, %d dblock, "
  2266.             "%d byte%s",
  2267.             unknown_bblockc, unknown_dblockc, unknown_sizec,
  2268.             (unknown_sizec == 1 ? "" : "s"));
  2269.   }
  2270. }
  2271.  
  2272. /*
  2273.  * log the heap structure plus information on the blocks if necessary
  2274.  */
  2275. EXPORT    void    _chunk_log_heap_map(void)
  2276. {
  2277.   /* did we map the heap second ago? */
  2278.   if (! BIT_IS_SET(_malloc_debug, DEBUG_CHECK_HEAP) ||
  2279.       ! BIT_IS_SET(_malloc_debug, DEBUG_HEAP_CHECK_MAP))
  2280.     log_heap_map();
  2281. }
  2282.